Fix getcwd() failed error in subshells and directory operations (#44)#105
Conversation
Adding CLAUDE.md with task information for AI processing. This file will be removed when the task is complete. Issue: #44
This change addresses issue #44 where getcwd() system call failures would cause command-stream to crash in certain scenarios, particularly when the current directory has been deleted or permissions have changed. Changes: - Added error handling around process.cwd() calls in _runSubshell method - Improved directory restoration logic with comprehensive fallback handling - Added graceful handling when original directory cannot be obtained - Enhanced error logging with better context information The fix ensures that: - Commands continue to work even when getcwd() fails - Directory restoration gracefully falls back to safe locations (HOME, /, etc.) - No unhandled exceptions are thrown due to directory access issues - CI/CD environments with temporary directories work reliably Tests added: - Comprehensive test cases for getcwd() error scenarios - Subshell-specific error handling tests - Directory restoration error handling tests - Debug examples for reproducing the issue 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
|
We need get latest changes from default branch, resolve conflicts, and make sure we reproduce, test these case, and if they really fail - fix them. |
|
🤖 AI Work Session Started Starting automated work session at 2026-06-10T14:05:04.288Z The PR has been converted to draft mode while work is in progress. This comment marks the beginning of an AI work session. Please wait for the session to finish, and provide your feedback. |
# Conflicts: # js/examples/debug-getcwd-error.mjs # js/examples/debug-subshell-getcwd.mjs # js/tests/getcwd-error-handling.test.mjs # src/$.mjs
Re-apply the getcwd() error handling to the modular ProcessRunner after the monorepo restructure. process.cwd() throws "getcwd() failed" when the current directory has been deleted or becomes inaccessible (common in CI/CD with temporary directories). - Add safeCwd() helper that returns null instead of throwing - _runSubshell captures the cwd via safeCwd() so it no longer crashes - restoreCwd() falls back to a safe location when the saved dir is gone/null - _runSimpleCommand falls back to the inherited cwd when getcwd() fails - Rewrite tests to genuinely reproduce the bug (fails without the fix) - Add changeset 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
|
Addressed the feedback:
|
🤖 Solution Draft LogThis log file contains the complete execution trace of the AI solution draft process. 💰 Cost: $2.941017📊 Context and tokens usage:
Total: (3.6K new + 68.9K cache writes + 3.6M cache reads) input tokens, 27.0K output tokens, $2.941017 cost 🤖 Models used:
📎 Log file uploaded as Gist (1666KB)Now working session is ended, feel free to review and add any feedback on the solution draft. |
🔄 Auto-restart triggered (iteration 1)Reason: CI failures detected Starting new session to address the issues. Auto-restart-until-mergeable mode is active. This run will stop after 5 restart iterations. |
⏳ Usage Limit ReachedThe automated solution draft was interrupted because the Anthropic Claude Code usage limit was reached. 📊 Limit Information
🔄 How to ContinueAuto-restart is enabled. The session will automatically restart (fresh start) when the limit resets. 🤖 Models used:
📎 Execution log uploaded as Gist (3897KB)This session was interrupted due to usage limits. The session will automatically restart when the limit resets. |
The previous getcwd() fix prevented process.cwd() from throwing, but a child process spawned with an inherited (deleted) working directory still failed at the OS level with 'posix_spawn ENOENT' on Linux/Windows. This caused the 'subshell runs even when the real working directory was deleted' regression test to fail on those platforms. - Add resolveSpawnCwd() in $.shell.mjs: when no explicit cwd is given and process.cwd() fails, spawn from a valid fallback directory instead of inheriting the broken one. Applied in both async and sync spawn paths. - Mirror the change in the Rust implementation (resolve_spawn_cwd in lib.rs, used by ProcessRunner and Pipeline) to satisfy JS/Rust parity. - Add a Rust regression test (rust/tests/getcwd_error_handling.rs). - Keep $.process-runner-execution.mjs under the 1500-line lint limit by housing the helper in $.shell.mjs.
🔄 Auto-restart triggered (iteration 2)Reason: CI failures detected Starting new session to address the issues. Auto-restart-until-mergeable mode is active. This run will stop after 5 restart iterations. |
process.cwd() does not reliably throw when the working directory has been deleted; under Bun it returns a stale path that no longer exists. resolveSpawnCwd() now validates the directory with fs.existsSync() instead of relying on process.cwd() to throw, and falls back to a known-good directory when an explicit cwd is missing or gone. Fixes the CI failure in the deleted-working-directory regression test on Linux.
Windows locks the current working directory, so fs.rmSync on the cwd throws EBUSY and the deleted-working-directory scenario cannot occur. Skip the regression test on Windows, matching the Rust suite.
Working session summaryAll checks pass. The two previously-failing CI checks are now green. SummaryThe PR for issue #44 had two failing CI checks ( 1. Linux/ubuntu — real bug in The fix validates the directory with 2. Windows — invalid test scenario Verification: All 21 CI checks pass — PR: #105 This summary was automatically extracted from the AI working session output. |
🔄 Auto-restart-until-mergeable Log (iteration 2)This log file contains the complete execution trace of the AI solution draft process. 💰 Cost: $1.946130📊 Context and tokens usage:
Total: (3.8K new + 54.3K cache writes + 2.4M cache reads) input tokens, 15.9K output tokens, $1.946130 cost 🤖 Models used:
📎 Log file uploaded as Gist (6283KB)Now working session is ended, feel free to review and add any feedback on the solution draft. |
✅ Ready to mergeThis pull request is now ready to be merged:
Monitored by hive-mind with --auto-restart-until-mergeable flag |
Summary
Fixes issue #44 where
getcwd()system call failures would crash command-stream during subshell execution.process.cwd()throwsgetcwd() failed: No such file or directorywhen the current working directory has been deleted or becomes inaccessible — common in CI/CD pipelines that run inside temporary directories that get cleaned up.This PR merges the latest
main(which restructured the repo into thejs/+rust/monorepo layout) and re-applies the getcwd() fix to the new modularProcessRunnerarchitecture.Root cause
In the refactored architecture, subshell execution lives in
js/src/$.process-runner-orchestration.mjs. The_runSubshellmethod calledconst savedCwd = process.cwd();with no error handling. Whengetcwd()fails, this throws and the whole command rejects:Changes
safeCwd()helper — returnsnullinstead of throwing whenprocess.cwd()fails._runSubshell— captures the directory viasafeCwd(), so it no longer crashes whengetcwd()fails.restoreCwd()— handles anullsaved directory and falls back to a safe location (HOME→USERPROFILE→/) when the original directory is gone orchdirfails._runSimpleCommand— falls back to the inheritedcwdwhengetcwd()is unavailable.patchbump.Reproduction
Test coverage
js/tests/getcwd-error-handling.test.mjsis a genuine regression test — it fails without the fix and passes with it:$ bun test js/tests/getcwd-error-handling.test.mjs ✅ 4 pass, 0 fail (with fix) ❌ 3 pass, 1 fail (without fix — confirms reproduction)It covers:
process.cwd()always failing, failing only inside_runSubshell, repeated commands after failures, and a real deleted-working-directory scenario.The full JS suite passes except for pre-existing
jq-not-installed environmental failures (same onmain).Verification
main, conflicts resolved (repo restructure:src/→js/src/,tests/→js/tests/)bun run lint,prettier --check,jscpdall clean🤖 Generated with Claude Code
Resolves #44